"""
  Copyright (c) 2024 Northeastern University (China)
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
"""
import click
import argparse
import json
import os

from src.common_utils.utils_file import write_line_jl
from src.component_identification.automated_verification import Verification
from src.component_identification.component_detector import Detector
from src.dependency_construction.build_dependency import BuildDependency
from src.dependency_construction.extraction_feature_dependency import ExtractionFeature
from src.dependency_construction.partition_module import PartitionModule

# 当前文件的路径
g_cur_dir = os.path.dirname(os.path.abspath(__file__))
# 当前文件的父路径
father_path = os.path.dirname(g_cur_dir)

def parameter_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument("--target_src_path", type=str, required=True, help="Path to target source")
    parser.add_argument("--component_output_path",type=str,default=None, help="Path to  component output")
    parser.add_argument("--deps_output_path", type=str, default=None, help="Path to component output")
    parser.add_argument("--theta", type=float, default=0.7, help="Description for theta parameter")
    parser.add_argument("--beta", type=float,default=0.6, help="Description for theta parameter")
    parser.add_argument("--cpu", type=int, default=8)
    return parser.parse_args()
def CompoRelAnalyticaMain(theta,beta,target_src_path,resDict=None,cpu=8):
    """
    整个程序的入口
    @param theta: 成分检测需要的参数，表示每个文件有多少比例代码呗复制
    @param beta: 成分检测需要的参数，表示有多少比例文件被复制
    @param target_src_path: 需要检测的目标代码绝对路径，必要参数
    @param resDict: 需要检测的目标代码的哈希结果，非必要参数，一般是通过程序生成
    @param cpu: 成分检测时并发执行的进程数量
    @return:
    """
    analysis_detect=None
    mid_res=None
    module_dic=None
    final_dependency=None
    visualization_data=None
    detector = Detector(theta,beta)
    target_src_repo = os.path.basename(target_src_path)
    print(f"1.成分识别")
    if resDict is None:
        resDict, fileCnt, funcCnt, lineCnt = detector.hashing(target_src_path)
    if len(resDict) != 0:
        components, mid_res = detector.detector_main(resDict, cpu)
        if components is not None:
            components=list(components)  #将multiprocessing.managers.ListProxy转换成正常list
            # 自动化验证
            verification = Verification()
            analysis_detect = verification.analysis_common(components, target_src_path)  # 这就得到了可视化中的节点列表
            final_dependency=[]
            if len(components)>1:
                print(f"2.成分依赖构建")
                # 划分模块
                partitionModule = PartitionModule()
                module_dic = partitionModule.main(components, target_src_path)
                # 提取特征
                extraction_feature = ExtractionFeature()
                target_features, dependency_dic = extraction_feature.main(module_dic,target_src_path=target_src_path)
                # 构建依赖
                buildDependency = BuildDependency()
                final_dependency = buildDependency.build_dependency(dependency_dic,target_features,target_path=target_src_path)
            edges = []
            nodes = [
                {
                    'id': 'target_code',
                    'repo_name': target_src_repo
                }
            ]
            print(f"生成可视化数据:")
            for data in analysis_detect:
                repo_name_index = data['name'].rfind("_")
                repo_name = data['name']
                if repo_name_index != -1:
                    repo_name = repo_name[:repo_name_index]
                data['id'] = data['name']
                data['repo_name'] = repo_name
                nodes.append(data)
                edges.append({
                    'source': 'target_code',
                    'target': data['name']
                })
            edges_copy = edges.copy()
            for edge in edges_copy:
                for dep_edge in final_dependency:
                    if edge['target'] == dep_edge['target']:
                        if edge in edges:
                            edges.remove(edge)
            edges.extend(final_dependency)
            visualization_data = {'nodes': nodes, 'edges': edges}
        else:
            print(f"目标代码没有其他开源成分")
    else:
        print(f"目标代码非C项目")
    return resDict, analysis_detect, mid_res, module_dic, final_dependency, visualization_data

@click.command()
@click.option('--target_src_path', type=str, required=True, help='Path to target source')
@click.option('--component_output_path', type=str, default=None, help='Path to component output')
@click.option('--deps_output_path', type=str, default=None, help='Path to component output')
@click.option('--theta', type=float, default=0.7, help='Description for theta parameter')
@click.option('--beta', type=float, default=0.6, help='Description for theta parameter')
@click.option('--cpu', type=int, default=8, help='Number of CPU cores')
def detect(target_src_path, component_output_path, deps_output_path, theta, beta, cpu):
    """
    对外暴露接口
    @param target_src_path: 目标代码路径
    @param component_output_path:
    @param deps_output_path:
    @param theta: 阈值
    @param beta:
    @param cpu: 并发执行进程数
    @return:
    """
    resDict, components, mid_res, module_dic, final_dependency, visualization_data = CompoRelAnalyticaMain(
        theta=theta, beta=beta, target_src_path=target_src_path,cpu=cpu)
    target_src_repo = os.path.basename(target_src_path)
    if component_output_path is not None:
        write_line_jl(os.path.join(component_output_path, target_src_repo + '_components.json'),components)
    print(f"components={components}")
    if deps_output_path is not None:
        with open(os.path.join(deps_output_path, target_src_repo + '_deps.json'), "w") as json_file:
            json.dump(visualization_data, json_file)
    print(f"depsdata={visualization_data}")


if __name__ == "__main__":
    detect()